﻿using System;
using System.Collections.Generic;
using System.Collections;
using Bling.Util;
using Bling.DSL;
using Bling.Core;
using Bling.Vecs;
namespace Bling.Core {
  public partial class TimeSpanBl : NumericBrand<TimeSpan, TimeSpanBl, TimeSpan, D1, TimeSpanBl> {
    public TimeSpanBl() : base() { }
    public TimeSpanBl(Expr<TimeSpan> e) : base(e) { }
    public TimeSpanBl(Expr<IVec<TimeSpan,D1>> e) : base(e) { }
    public static implicit operator TimeSpanBl(Expr<TimeSpan> t) { return new TimeSpanBl(t); }
    public static implicit operator TimeSpanBl(TimeSpan t) { return new Constant<TimeSpan>(t); }
  }
  public partial class ColorBl : DoubleBl<IVec<double, D4>, ColorBl, D4>, IHasXYZW<double, DoubleBl> {
    public ColorBl(Expr<IVec<double, D4>> Underlying) : base(Underlying) { }
    public ColorBl(DoubleBl ScR, DoubleBl ScG, DoubleBl ScB, DoubleBl ScA) : base(ScR, ScG, ScB, ScA) { }
    public ColorBl(DoubleBl ScR, DoubleBl ScG, DoubleBl ScB) : base(ScR, ScG, ScB, 1d) { }
    public ColorBl(RgbBl ScRGB, DoubleBl ScA) : base(CombineOp<D3, D1>.Instance.Make(ScRGB, ScA)) { }
    public ColorBl() : base() { }

    public DoubleBl ScR { get { return this[0]; } }
    public DoubleBl ScG { get { return this[1]; } }
    public DoubleBl ScB { get { return this[2]; } }
    public DoubleBl ScA { get { return this[3]; } }
    public RgbBl ScRGB { get { return (RgbBl)this.XYZ(); } }

    public static implicit operator ColorBl(Expr<IVec<double, D4>> U) { return new ColorBl(U); }
    public static explicit operator Double4Bl(ColorBl clr) { return clr.Provider; }
    public static explicit operator ColorBl(Double4Bl clr) { return clr.Provider; }



    public static implicit operator ColorBl(DoubleBl d) { return Repeat(d); }
    public static implicit operator ColorBl(double d) { return Repeat(d); }

    public class ColorToRGBOp : UnaryOperatorS<IVec<double, D3>, ColorToRGBOp>, INoShaderOperator, INoLinqOperator {
      public new static readonly ColorToRGBOp Instance = new ColorToRGBOp();
      private ColorToRGBOp() { }
      public override string Name {
        get { return "ToRGB"; }
      }
      public override Expr<IVec<double, D3>> Expand(Expr<IVec<double, D4>> argA) {
        return ((ColorBl)argA).ScRGB;
      }
      public override Expr<IVec<double, D4>> Inverse(Expr<IVec<double, D4>> argA, Expr<IVec<double, D3>> result) {
        RgbBl color = result;
        return ((ColorBl)color);
      }
    }
    public static explicit operator RgbBl(ColorBl clr) {
      return ColorToRGBOp.Instance.Make(clr);
    }
  }

  public partial class RgbBl : DoubleBl<IVec<double, D3>, RgbBl, D3>, IHasXYZ<DoubleBl> {
    public RgbBl(Expr<IVec<double, D3>> Underlying) : base(Underlying) { }
    public RgbBl(DoubleBl ScR, DoubleBl ScG, DoubleBl ScB) : base(ScR, ScG, ScB) { }
    public RgbBl() : base() { }



    /// <summary>
    /// Reflectance coefficient of a material, between 0 ~ 1. 
    /// This will set the RGB value to White * value.
    /// </summary>
    public DoubleBl Factor { set { this.Bind = value; } }
    public class RGBToColorOp : UnaryOperatorS<IVec<double, D4>, RGBToColorOp>, INoShaderOperator, INoLinqOperator {
      public new static readonly RGBToColorOp Instance = new RGBToColorOp();
      private RGBToColorOp() { }
      public override string Name {
        get { return "ToColor"; }
      }
      public override Expr<IVec<double, D4>> Expand(Expr<IVec<double, D3>> argA) {
        RgbBl rgb = argA;
        return new ColorBl(rgb, 1d);
      }
      public override Expr<IVec<double, D3>> Inverse(Expr<IVec<double, D3>> argA, Expr<IVec<double, D4>> result) {
        ColorBl color = result;
        return (RgbBl)color;
      }
    }
    public static implicit operator ColorBl(RgbBl clr) {
      return RGBToColorOp.Instance.Make(clr);
    }
    public DoubleBl ScR { get { return this[0]; } }
    public DoubleBl ScG { get { return this[1]; } }
    public DoubleBl ScB { get { return this[2]; } }

    public static implicit operator RgbBl(Expr<IVec<double, D3>> U) { return new RgbBl(U); }
    public static implicit operator RgbBl(DoubleBl d) { return Repeat(d); }
    public static implicit operator RgbBl(double d) { return Repeat(d); }
    public static explicit operator Double3Bl(RgbBl clr) { return clr.Provider; }
    public static explicit operator RgbBl(Double3Bl clr) { return clr.Provider; }
  }

}

namespace Bling.Core {
  public abstract partial class FunctionBl<RET, BRAND> : IValueBrand<BRAND>, ICanMakeParam<BRAND>
    where RET : ICanMakeParam<RET>
    where BRAND : FunctionBl<RET, BRAND> {
    public BRAND ChooseA(BoolBl Test, BRAND IfFalse) {
      return Map(IfFalse, (IfTrue0, IfFalse0) => IfTrue0.ChooseA(Test, IfFalse0));
    }
    public StringBl ToStringBl() { return Id.ToStringBl(); }
    public BRAND Table(IntBl Index, BRAND[] Options) {
      return Map0(F => {
        RET[] Values = new RET[Options.Length];
        for (int i = 0; i < Options.Length; i++) Values[i] = F(Options[i]);
        return Values.Table(Index);
      });
    }
    public BoolBl Equal(BRAND Other) { return Id.Equal(Other.Id); }

    protected static readonly Func<Func<Func<BRAND, RET>, RET>, BRAND> Map0;
    static FunctionBl() {
      var mthd1 = typeof(BRAND).GetConstructor(new Type[] { typeof(Func<Func<BRAND, RET>, RET>) });
      if (mthd1 != null) {
        Map0 = arg => (BRAND)mthd1.Invoke(new object[] { arg });
      } else {
        var mthd0 = typeof(BRAND).GetMethod("MakeFunc", new Type[] { typeof(Func<Func<BRAND, RET>, RET>) });
        (mthd0 != null).Assert();
        (mthd0.IsStatic && mthd0.ReturnType == typeof(BRAND)).Assert();
        Map0 = arg => (BRAND)mthd0.Invoke(null, new object[] { arg });
      }
      Params<BRAND>.Make0 = (id,name) => Map0(G => Params<RET>.Make0(id,name));
    }
    public BRAND Map(Func<RET, RET> F) {
      return Map0(G => F(G(this)));
    }
    public BRAND Map(BRAND Other, Func<RET, RET, RET> F) {
      return Map0(G => F(G(this), G(Other)));
    }
    public BRAND Map(BRAND OtherA, BRAND OtherB, Func<RET, RET, RET, RET> F) {
      return Map0(G => F(G(this), G(OtherA), G(OtherB)));
    }
    public BRAND Map(IList<BRAND> Others, Func<RET, IList<RET>, RET> F) {
      return Map0(G => {
        var Rs = new RET[Others.Count];
        for (int i = 0; i < Rs.Length; i++) Rs[i] = G(Others[i]);
        return F(G(this), Rs);
      });
    }
    public RET Id { get { return MakeID(""); } }
    public abstract RET MakeID(string Prefix);
    public override string ToString() { return Id.ToString(); }
    public override int GetHashCode() { return Id.GetHashCode(); }
    public override bool Equals(object obj) {
      if (obj is BRAND) return ((BRAND)obj).Id.Equals(Id);
      else return base.Equals(obj);
    }
    /*
    public StringBl ToStringBl() {
      return Id.ToStringBl();
    }*/
    public static implicit operator BRAND(FunctionBl<RET, BRAND> f) { return (BRAND)f; }

  }
  public abstract partial class FunctionBl<RET, FUNC, BRAND> : FunctionBl<RET,BRAND>
    where RET : ICanMakeParam<RET>
    where BRAND : FunctionBl<RET, FUNC, BRAND> {
    public readonly FUNC Function;
    public FunctionBl(FUNC Function) { this.Function = Function; }

    public static readonly Func<FUNC, BRAND> ToBrand;
    static FunctionBl() {
      var mthd = typeof(BRAND).GetConstructor(new Type[] { typeof(FUNC) });
      (mthd != null).Assert();
      ToBrand = f => (BRAND) mthd.Invoke(new object[] { f });
    }
    public static implicit operator FUNC(FunctionBl<RET, FUNC, BRAND> F) { return F.Function; }
  }
  public partial class FlexFunctionBl<ARG0, RET> : FunctionBl<RET, Func<ARG0, RET>, FlexFunctionBl<ARG0, RET>>
    where RET : ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0> {
    public FlexFunctionBl(Func<ARG0, RET> Function) : base(Function) { }
    public FlexFunctionBl(Func<Func<FlexFunctionBl<ARG0, RET>, RET>, RET> F)
      : this(new Func<ARG0, RET>(arg => F(x => x[arg]))) { }

    public RET this[ARG0 arg] { get { return Function(arg); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix + "_A")];
    }
  }
  public partial class FlexFunctionBl<ARG0, ARG1, RET> : FunctionBl<RET, Func<ARG0, ARG1, RET>, FlexFunctionBl<ARG0, ARG1, RET>>
    where RET : ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0>
    where ARG1 : ICanMakeParam<ARG1> {
    public FlexFunctionBl(Func<ARG0, ARG1, RET> Function) : base(Function) { }
    public FlexFunctionBl(Func<Func<FlexFunctionBl<ARG0, ARG1, RET>, RET>, RET> F)
      : this(new Func<ARG0, ARG1, RET>((arg0,arg1) => F(x => x[arg0, arg1]))) { }

    public RET this[ARG0 arg0, ARG1 arg1] { get { return Function(arg0, arg1); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix+"_A"), Params<ARG1>.Make(Prefix+"_B")];
    }
  }
  public partial class FlexFunctionBl<ARG0, ARG1, ARG2, RET> : FunctionBl<RET, Func<ARG0, ARG1, ARG2, RET>, FlexFunctionBl<ARG0, ARG1, ARG2, RET>>
    where RET : ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0>
    where ARG1 : ICanMakeParam<ARG1>
    where ARG2 : ICanMakeParam<ARG2> {
    public FlexFunctionBl(Func<ARG0, ARG1, ARG2, RET> Function) : base(Function) { }
    public FlexFunctionBl(Func<Func<FlexFunctionBl<ARG0, ARG1, ARG2, RET>, RET>, RET> F)
      : this(new Func<ARG0, ARG1, ARG2, RET>((arg0, arg1, arg2) => F(x => x[arg0, arg1, arg2]))) { }

    public RET this[ARG0 arg0, ARG1 arg1, ARG2 arg2] { get { return Function(arg0, arg1, arg2); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix +"_A"), Params<ARG1>.Make(Prefix+"_B"), Params<ARG2>.Make(Prefix+"_C")];
    }
  }

  public abstract partial class BaseNumFuncBl<RET, FUNC, BRAND> : FunctionBl<RET, FUNC, BRAND>, INumeric<BRAND>
    where RET : INumeric<RET>, ICanMakeParam<RET>
    where BRAND : NumFuncBl<RET, FUNC, BRAND> {
    public BaseNumFuncBl(FUNC Function) : base(Function) { }

    public virtual BRAND Add(BRAND OpB) { return Map(OpB, (opA, opB) => opA.Add(opB)); }
    public virtual BRAND Subtract(BRAND OpB) { return Map(OpB, (opA, opB) => opA.Subtract(opB)); }
    public virtual BRAND Multiply(BRAND OpB) { return Map(OpB, (opA, opB) => opA.Multiply(opB)); }
    public virtual BRAND Divide(BRAND OpB) { return Map(OpB, (opA, opB) => opA.Divide(opB)); }
    public virtual BRAND Mod(BRAND OpB) { return Map(OpB, (opA, opB) => opA.Mod(opB)); }
    public virtual BRAND Negate { get { return Map(opA => opA.Negate); } }
    /// <summary>
    ///     Returns the absolute value of a number.
    /// </summary>
    public virtual BRAND Abs { get { return Map(opA => opA.Abs); } }
    /// <summary>
    /// Returns the smaller of two numbers.
    /// </summary>
    public virtual BRAND Min(BRAND other) { return Map(other, (opA, opB) => opA.Min(opB)); }
    /// <summary>
    /// Returns the larger of two numbers.
    /// </summary>
    public virtual BRAND Max(BRAND other) { return Map(other, (opA, opB) => opA.Max(opB)); }
    /// <summary>
    /// Clamps the specified value to the specified minimum and maximum range.    
    /// </summary>
    public virtual BRAND Clamp(BRAND min, BRAND max) { return Map(min, max, (at, min0, max0) => at.Clamp(min0, max0)); }

    public static BRAND operator +(BaseNumFuncBl<RET, FUNC, BRAND> opA, BRAND opB) { return opA.Add(opB); }
    public static BRAND operator -(BaseNumFuncBl<RET, FUNC, BRAND> opA, BRAND opB) { return opA.Subtract(opB); }
    public static BRAND operator *(BaseNumFuncBl<RET, FUNC, BRAND> opA, BRAND opB) { return opA.Multiply(opB); }
    public static BRAND operator /(BaseNumFuncBl<RET, FUNC, BRAND> opA, BRAND opB) { return opA.Divide(opB); }
    public static BRAND operator %(BaseNumFuncBl<RET, FUNC, BRAND> opA, BRAND opB) { return opA.Mod(opB); }
    public static BRAND operator -(BaseNumFuncBl<RET, FUNC, BRAND> opA) { return opA.Negate; }
  }
  public abstract partial class NumFuncBl<RET, FUNC, BRAND> : BaseNumFuncBl<RET, FUNC, BRAND>
    where RET : INumeric<RET>, ICanMakeParam<RET>
    where BRAND : NumFuncBl<RET, FUNC, BRAND> {
    public NumFuncBl(FUNC Function) : base(Function) { }

    public static BRAND operator +(BRAND opA, NumFuncBl<RET, FUNC, BRAND> opB) { return opA.Add(opB); }
    public static BRAND operator -(BRAND opA, NumFuncBl<RET, FUNC, BRAND> opB) { return opA.Subtract(opB); }
    public static BRAND operator *(BRAND opA, NumFuncBl<RET, FUNC, BRAND> opB) { return opA.Multiply(opB); }
    public static BRAND operator /(BRAND opA, NumFuncBl<RET, FUNC, BRAND> opB) { return opA.Divide(opB); }
    public static BRAND operator %(BRAND opA, NumFuncBl<RET, FUNC, BRAND> opB) { return opA.Mod(opB); }
  }
  public partial class FlexNumFuncBl<ARG0, RET> : NumFuncBl<RET, Func<ARG0, RET>, FlexNumFuncBl<ARG0, RET>>
    where RET : ICanMakeParam<RET>, INumeric<RET>
    where ARG0 : ICanMakeParam<ARG0> {
    public FlexNumFuncBl(Func<ARG0, RET> Function) : base(Function) { }
    public FlexNumFuncBl(Func<Func<FlexFunctionBl<ARG0, RET>, RET>, RET> F)
      : this(new Func<ARG0, RET>(arg => F(x => x[arg]))) { }
    public static implicit operator FlexNumFuncBl<ARG0, RET>(Func<ARG0, RET> F) { return new FlexNumFuncBl<ARG0, RET>(F); }

    public RET this[ARG0 arg] { get { return Function(arg); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix + "_A")];
    }
  }

  public abstract partial class BaseDoubleFuncBl<RET, FUNC, BRAND> : NumFuncBl<RET, FUNC, BRAND>, IDouble<BRAND>
    where RET : IDouble<RET>, ICanMakeParam<RET>
    where BRAND : DoubleFuncBl<RET, FUNC, BRAND> {
    public BaseDoubleFuncBl(FUNC Function) : base(Function) { }

    public Func<object, object, DoubleBl, object> BaseCoreInterpolate {
      get { return (x, y, t) => CoreInterpolate((BRAND)x, (BRAND)y, t); }
    }
    public Func<BRAND, BRAND, DoubleBl, BRAND> CoreInterpolate {
      get {
        return (x0, y0, t) => x0.Map(y0, (x, y) => x.CoreInterpolate(x, y, t));
      }
    }

    public BRAND Saturate { get { return Map(r => r.Saturate); } }
    public BRAND Floor { get { return Map(r => r.Floor); } }
    public BRAND Ceiling { get { return Map(r => r.Ceiling); } }
    public BRAND Round { get { return Map(r => r.Round); } }
    public BRAND Exp { get { return Map(r => r.Exp); } }
    public BRAND Log { get { return Map(r => r.Log); } }
    public BRAND Exp2 { get { return Map(r => r.Exp2); } }
    public BRAND Log2 { get { return Map(r => r.Log2); } }
    public BRAND Exp10 { get { return Map(r => r.Exp10); } }
    public BRAND Log10 { get { return Map(r => r.Log10); } }
    public BRAND Pow(BRAND Power) { return Map(Power, (a, b) => a.Pow(b)); }
    public BRAND LogN(BRAND Base) { return Map(Base, (a, b) => a.LogN(b)); }
    public BRAND Recip { get { return Map(r => r.Recip); } }
    public BRAND Square { get { return Map(r => r.Square); } }
    public BRAND Sqrt { get { return Map(r => r.Sqrt); } }
    public BRAND Rsqrt { get { return Map(r => r.Rsqrt); } }
    public BRAND Ddx { get { return Map(r => r.Ddx); } }
    public BRAND Ddy { get { return Map(r => r.Ddy); } }
    public BRAND Fwidth { get { return Map(r => r.Fwidth); } }
    public BRAND Frac { get { return Map(r => r.Frac); } }
    public BRAND Ldexp(BRAND other) { return Map(other, (a, b) => a.Ldexp(b)); }
    public BRAND RawNormalize { get { return Map(r => r.RawNormalize); } }
    public BRAND Normalize { get { return Map(r => r.Normalize); } }
  }
  public abstract partial class DoubleFuncBl<RET, FUNC, BRAND> : BaseDoubleFuncBl<RET, FUNC, BRAND>
    where RET : IDouble<RET>, ICanMakeParam<RET>
    where BRAND : DoubleFuncBl<RET, FUNC, BRAND> {
    public DoubleFuncBl(FUNC Function) : base(Function) { }
  }

  public abstract partial class ArgDoubleFuncBl<ARG0, RET, BRAND> : DoubleFuncBl<RET, Func<ARG0, RET>, BRAND>
    where RET : IDouble<RET>, ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0> 
    where BRAND : ArgDoubleFuncBl<ARG0,RET,BRAND> {
    public ArgDoubleFuncBl(Func<ARG0, RET> Function) : base(Function) { }
    public ArgDoubleFuncBl(Func<Func<BRAND, RET>, RET> F)
      : this(new Func<ARG0, RET>(arg => F(x => x[arg]))) { }

    public RET this[ARG0 arg] { get { return Function(arg); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix + "_A")];
    }
  }
  public partial class DoubleFuncBl<ARG0, ARG1, RET, BRAND> : DoubleFuncBl<RET, Func<ARG0, ARG1, RET>, BRAND>
    where RET : IDouble<RET>, ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0>
    where ARG1 : ICanMakeParam<ARG1>
    where BRAND : DoubleFuncBl<ARG0, ARG1, RET, BRAND> {
    public DoubleFuncBl(Func<ARG0, ARG1, RET> Function) : base(Function) { }
    public DoubleFuncBl(Func<Func<BRAND, RET>, RET> F)
      : this(new Func<ARG0, ARG1, RET>((arg0, arg1) => F(x => x[arg0, arg1]))) { }

    public RET this[ARG0 arg0, ARG1 arg1] { get { return Function(arg0, arg1); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix + "_A"), Params<ARG1>.Make(Prefix + "_B")];
    }
  }
  public partial class DoubleFuncBl<ARG0, ARG1, ARG2, RET, BRAND> : DoubleFuncBl<RET, Func<ARG0, ARG1, ARG2, RET>, BRAND>
    where RET : IDouble<RET>, ICanMakeParam<RET>
    where ARG0 : ICanMakeParam<ARG0>
    where ARG1 : ICanMakeParam<ARG1>
    where ARG2 : ICanMakeParam<ARG2>
    where BRAND : DoubleFuncBl<ARG0, ARG1, ARG2, RET, BRAND> {
    public DoubleFuncBl(Func<ARG0, ARG1, ARG2, RET> Function) : base(Function) { }
    public DoubleFuncBl(Func<Func<BRAND, RET>, RET> F)
      : this(new Func<ARG0, ARG1, ARG2, RET>((arg0, arg1, arg2) => F(x => x[arg0, arg1, arg2]))) { }

    public RET this[ARG0 arg0, ARG1 arg1, ARG2 arg2] { get { return Function(arg0, arg1, arg2); } }
    public override RET MakeID(string Prefix) {
      return this[Params<ARG0>.Make(Prefix + "_A"), Params<ARG1>.Make(Prefix + "_B"), Params<ARG2>.Make(Prefix + "_C")];
    }
  }
  public static class FunctionExtensions {



    public static BRAND Compose<RET, BRAND>(this FunctionBl<RET, Func<RET, RET>, BRAND> F0, BRAND F1)
      where RET : IConditionTarget<RET>, ICanMakeParam<RET>
      where BRAND : FunctionBl<RET, Func<RET, RET>, BRAND> {
      return FunctionBl<RET, Func<RET, RET>, BRAND>.ToBrand(ret => F0.Function(F1.Function(ret)));
    }
    public static BRAND Compose<RET, ARG0, BRAND>(this FunctionBl<RET, Func<RET, ARG0, RET>, BRAND> F0, BRAND F1)
      where RET : IConditionTarget<RET>, ICanMakeParam<RET>
      where BRAND : FunctionBl<RET, Func<RET, ARG0, RET>, BRAND> {
      return FunctionBl<RET, Func<RET, ARG0, RET>, BRAND>.ToBrand((ret,arg) => F0.Function(F1.Function(ret, arg), arg));
    }
    public static BRAND Compose<RET, ARG0, ARG1, BRAND>(this FunctionBl<RET, Func<RET, ARG0, ARG1, RET>, BRAND> F0, BRAND F1)
      where RET : IConditionTarget<RET>, ICanMakeParam<RET>
      where BRAND : FunctionBl<RET, Func<RET, ARG0, ARG1, RET>, BRAND> {
      return FunctionBl<RET, Func<RET, ARG0, ARG1, RET>, BRAND>.ToBrand(
        (ret, arg0, arg1) => F0.Function(F1.Function(ret, arg0, arg1), arg0, arg1));
    }

    public static FlexFunctionBl<ARG,RET0> MapR<ARG,RET,RET0,BRAND>(this FunctionBl<RET, Func<ARG, RET>, BRAND> F0, Func<RET,RET0> G)
      where RET : IConditionTarget<RET>, ICanMakeParam<RET>
      where RET0 : IConditionTarget<RET0>, ICanMakeParam<RET0>
      where ARG : Brand<ARG>, IValueBrand<ARG>
      where BRAND : FunctionBl<RET, Func<ARG, RET>, BRAND> {
      return FlexFunctionBl<ARG, RET0>.ToBrand(arg => G(F0.Function(arg)));
    }
    public static FlexFunctionBl<ARG, RET0> MapR<ARG, RET, RET0, BRAND>(this FunctionBl<RET, Func<ARG, RET>, BRAND> F0, BRAND F1, Func<RET, RET, RET0> G)
      where RET : IConditionTarget<RET>, ICanMakeParam<RET>
      where RET0 : IConditionTarget<RET0>, ICanMakeParam<RET0>
      where ARG : Brand<ARG>, IValueBrand<ARG>
      where BRAND : FunctionBl<RET, Func<ARG, RET>, BRAND> {
      return FlexFunctionBl<ARG, RET0>.ToBrand(arg => G(F0.Function(arg), F1.Function(arg)));
    }


  }


}